package solvoku.model.solver;

import java.util.ArrayList;
import solvoku.model.game.Case;
import solvoku.model.game.CoupAJouer;
import solvoku.model.game.Grille;
import solvoku.model.solver.exceptions.ValeursGrilleException;

/**
 *
 * @author Steve Cancès <steve.cances@gmail.com>
 */
public class Solver {

    private Grille grilleResolue;
    private Grille grille;
    private ArrayList<CoupAJouer> coupsAJouer;
    private boolean solvable;

    /**
     * Construit le solver avec les valeurs des case
     *
     * @param values les valeurs des cases
     * @throws ValeursGrilleException Si le tableau de tableaux de valeurs de
     * cases n'est pas correcte
     */
    public Solver(Integer[][] values) throws ValeursGrilleException {
        if (values.length != 9) {
            throw new ValeursGrilleException();
        }
        for (Integer[] v : values) {
            if (v.length != 9) {
                throw new ValeursGrilleException();
            }
        }
        this.grilleResolue = new Grille(values);
        this.solvable = this.grilleResolue.resoudre();

        this.grille = new Grille(values);
        this.coupsAJouer = new ArrayList<>();

        Grille grilleTmp = new Grille(values);

        CoupAJouer coupAJouer;
        do {
            coupAJouer = grilleTmp.getCoupAJouerResolutionComplex();
            if (coupAJouer != null) {
                Case c = coupAJouer.getC();
                this.coupsAJouer.add(new CoupAJouer(this.grille.getCases()[c.getX()][c.getY()], coupAJouer.getValue()));
                coupAJouer.jouerCoup();
            }
        } while (coupAJouer != null);
    }

    public Grille getGrilleResolue() {
        return grilleResolue;
    }

    public Grille getGrille() {
        return grille;
    }
    
    /**
     * Retourne vrai si la grille est solvable et faux sinon
     *
     * @return vrai si la grille est solvable et faux sinon
     */
    public boolean isSolvable() {
        return this.solvable;
    }

    /**
     * Retourne un ArrayList contenant les coups a jouer (dans l'ordre où ils
     * ont été trouvé)
     *
     * @return un ArrayList contenant les coups a jouer (dans l'ordre où ils ont
     * été trouvé)
     */
    public ArrayList<CoupAJouer> getCoupsAJouer() {
        return this.coupsAJouer;
    }

    /**
     * Retourne le prochain coup a jouer (null s'il n'y a plus de coup a jouer)
     *
     * @return le prochain coup a jouer (null s'il n'y a plus de coup a jouer)
     */
    public CoupAJouer getProchainCoupAJouer() {
        CoupAJouer coupAJouer;
        if (this.coupsAJouer.isEmpty()) {
            coupAJouer = null;
        } else {
            coupAJouer = this.coupsAJouer.get(0);
        }
        return coupAJouer;
    }

    /**
     * Joue le prochain coup à jouer
     *
     * @return vrai si le coup a bien été joué et faux sinon (S'il n'y a plus de
     * coup a jouer)
     */
    public boolean jouerProchainCoupAJouer() {
        boolean res;
        if (this.coupsAJouer.isEmpty()) {
            res = false;
        } else {
            res = true;
            this.coupsAJouer.get(0).jouerCoup();
            this.coupsAJouer.remove(0);
        }
        return res;
    }
}
